
//sha1加密工具
let _sha1 = (function () {

    "use strict";

    let __b64pad = "";
    let __hex_case = 0;
    let __char_bit = 8;

    let __safe_add = function (x, y) {
        let lsw = (x & 0xFFFF) + (y & 0xFFFF);
        let msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    };

    let __rol = function (num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); };

    let __sha1_ft = function (t, b, c, d) {
        if (t < 20) return (b & c) | ((~b) & d);
        if (t < 40) return b ^ c ^ d;
        if (t < 60) return (b & c) | (b & d) | (c & d);
        return b ^ c ^ d;
    };

    let __sha1_kt = function (t) {
        return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514;
    };

    let __str_to_binary = function (str) {
        let  bin = Array();
        let  mask = (1 << __char_bit) - 1;
        for (let  i = 0; i < str.length * __char_bit; i += __char_bit)
            bin[i >> 5] |= (str.charCodeAt(i / __char_bit) & mask) << (24 - i % 32);
        return bin;
    }
    let __binary_to_str = function (bin) {
        let  str = "";
        let  mask = (1 << __char_bit) - 1;
        for (let  i = 0; i < bin.length * 32; i += __char_bit)
            str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask);
        return str;
    };

    let __binary_to_hex = function (binary) {
        let  hex_tab = __hex_case ? "0123456789ABCDEF" : "0123456789abcdef";
        let  str = "";
        for (let  i = 0; i < binary.length * 4; i++)
        {
            str += hex_tab.charAt((binary[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binary[i >> 2] >> ((3 - i % 4) * 8)) & 0xF);
        }
        return str;
    };

    let __binary_to_b64 = function (binary) {
        let  tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        let  str = "";
        for (let  i = 0; i < binary.length * 4; i += 3)
        {
            let  triplet = (((binary[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((binary[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | ((binary[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF);
            for (let  j = 0; j < 4; j++)
            {
                if (i * 8 + j * 6 > binary.length * 32) str += __b64pad;
                else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
            }
        }
        return str;
    };

    let __core_sha1 = function (x, len) {
        x[len >> 5] |= 0x80 << (24 - len % 32);
        x[((len + 64 >> 9) << 4) + 15] = len;

        let  w = Array(80);
        let  a = 1732584193;
        let  b = -271733879;
        let  c = -1732584194;
        let  d = 271733878;
        let  e = -1009589776;

        for (let  i = 0; i < x.length; i += 16)
        {
            let olda = a;
            let oldb = b;
            let oldc = c;
            let oldd = d;
            let olde = e;

            for (let  j = 0; j < 80; j++)
            {
                if (j < 16) w[j] = x[i + j];
                else w[j] = __rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
                let  t = __safe_add(__safe_add(__rol(a, 5), __sha1_ft(j, b, c, d)), __safe_add(__safe_add(e, w[j]), __sha1_kt(j)));
                e = d;
                d = c;
                c = __rol(b, 30);
                b = a;
                a = t;
            }

            a = __safe_add(a, olda);
            b = __safe_add(b, oldb);
            c = __safe_add(c, oldc);
            d = __safe_add(d, oldd);
            e = __safe_add(e, olde);
        }
        return Array(a, b, c, d, e);
    };

    let __core_hmac_sha1 = function (key, data) {
        let bkey = __str_to_binary(key);
        if (bkey.length > 16) bkey = __core_sha1(bkey, key.length * __char_bit);

        let ipad = Array(16),
            opad = Array(16);
        for (let  i = 0; i < 16; i++)
        {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5C5C5C5C;
        }

        let hash = __core_sha1(ipad.concat(__str_to_binary(data)), 512 + data.length * __char_bit);
        return __core_sha1(opad.concat(hash), 512 + 160);
    };

    //实例
    let __instance = null;
    //接口类
    let Class = function () {};

    //实现单例
    let GetInstance = function () {
        if (__instance == null)
        {
            __instance = new Class();
        }
        return __instance;
    };

    //对外接口，接受字符串参数并返回十六进制或base-64编码的字符串
    Class.prototype._hex_sha1 = function(s){ return __binary_to_hex(__core_sha1(__str_to_binary(s), s.length * __char_bit)); };
    Class.prototype._b64_sha1 = function(s){ return __binary_to_b64(__core_sha1(__str_to_binary(s), s.length * __char_bit)); };
    Class.prototype._str_sha1 = function(s){ return __binary_to_str(__core_sha1(__str_to_binary(s), s.length * __char_bit)); };
    Class.prototype._hex_hmac_sha1 = function(key, data) { return __binary_to_hex(__core_hmac_sha1(key, data)); };
    Class.prototype._b64_hmac_sha1 = function(key, data) { return __binary_to_b64(__core_hmac_sha1(key, data)); };
    Class.prototype._str_hmac_sha1 = function(key, data) { return __binary_to_str(__core_hmac_sha1(key, data)); };

    //执行一个简单的自检，看看虚拟机是否正常工作
    Class.prototype._sha1_vm_test = function () { return this._hex_sha1("abc") === "a9993e364706816aba3e25717850c26c9cd0d89d"; };

    //返回
    return GetInstance();

})();

//导出
export default _sha1;
